# 协程的本质就是在单线程下，由用户自己控制一个任务遇到io阻塞了就切换另外一个任务去执行，以此来提升效率
# 因此为了实现协程主要满足两个条件
#   1. 可以控制任务间执行的切换，并且能保存执行状态以便随时恢复
#   2. 可以检测io操作，在遇到io时自动完成切换
# yield表达式可以实现执行切换，是一种简单的协程，但是yield不能自动检测io进行自动切换
# 协程：
#   协程就是一种用户态的轻量级线程，实现单线程下的并发，又叫微线程、纤程，coroutine
#   协程由用户程序自己控制调度
# 注意：
#   1. python的线程是内核级别的，当一个线程io阻塞或者执行时间过长，就会被迫将cpu交出切换到其他线程执行
#   2. 协程就是在单线程中开启，一旦遇到io就会自动在应用级别控制切换，从而来提升效率
# 优点：
#   1. 协程切换开销小，属于程序级别，系统无感知，更加轻量级
#   2. 单线程内实现并发，最大限度利用cpu(对于非io型即计算型任务无法提高计算效率)
# 缺点：
#   协程本质是单线程，无法利用多核，可以一个程序开多个进程，每个进程开启多个线程，每个线程开启协程
# 特点：
#   1. 单线程实现并发
#   2. 修改共享数据不需要加锁
#   3. 用户程序中保存多个上下文执行栈
#   4. 一个协程遇到io自动会切换到其他协程

# 协程函数： 通过async def 修饰的函数为协程函数
# await 表达式、async for表达式、async with表达式只能用于协程函数体内  
# yield from不可用于协程函数内
import time
async def f1():
    print('f1 start')
    async for i in range(5):
        print(i)
        time.sleep(0.5)
    else :
        print('finish loop')

def f2():
    print('f2 start')
    f1()
    print('f2 end.')


if __name__ == '__main__':
    f2()
